﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Linq.Expressions;
using System.Collections;

namespace LibraryMusicStore
{
    public class Repository<T> : IRepository<T> where T : class
    {
        public MusicStoreEntities Context { get; set; }
        
        public Repository():this(new MusicStoreEntities())
        {}
        
        public Repository(MusicStoreEntities Context)
        {
            try
            {
                this.Context = Context;
            }
            catch (Exception)
            {
                throw;
            }
        }
    
        public virtual T GetById(int id)
        {
            try
            {
                var itemParameter = Expression.Parameter(typeof(T), "item");
                var whereExpression = Expression.Lambda<Func<T, bool>>
                    (
                    Expression.Equal(
                        Expression.Property(
                            itemParameter,
                            GetPrimaryKeyName<T>()
                            ),
                        Expression.Constant(id)
                        ),
                    new[] { itemParameter }
                    );
                var table = Context.GetTable<T>();
                return table.Where(whereExpression).Single();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public string GetPrimaryKeyName<T1>()
        {
            try
            {
                var type = Context.Mapping.GetMetaType(typeof(T1));

                var PK = (from m in type.DataMembers
                          where m.IsPrimaryKey
                          select m).Single();
                return PK.Name;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public T Single(Func<T, bool> exp)
        {
            try
            {
                return Context.GetTable<T>().Single(exp);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public T First(Func<T, bool> exp)
        {
            try
            {
                return Context.GetTable<T>().First(exp);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public T First()
        {
            try
            {
                return Context.GetTable<T>().First();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public virtual IQueryable<T> GetAll()
        {
            try
            {
                return Context.GetTable<T>();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        public virtual void InsertOnSubmit(T entity)
        {
            try
            {
                GetTable().InsertOnSubmit(entity);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public virtual void DeleteOnSubmit(T entity)
        {
            try
            {
                GetTable().DeleteOnSubmit(entity);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public virtual void SubmitChanges()
        {
            try
            {
                Context.SubmitChanges();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public virtual ITable GetTable()
        {
            try
            {
                return Context.GetTable<T>();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public void DeleteAllOnSubmit(IEnumerable entities)
        {
            try
            {
                GetTable().DeleteAllOnSubmit(entities);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool Duplicate(Func<T, bool> exp)
        {
            try
            {
                return Context.GetTable<T>().Where(exp).Count() > 0;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public IEnumerable<T> Where(Func<T, bool> exp)
        {
            try
            {
                return Context.GetTable<T>().Where(exp);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public MusicStoreEntities GetContext()
        {
            return this.Context;
        }

    }
}
